using Lazy.Captcha.Core.Generator;
using Com.Core.Module.Filters;
using Serilog;
using Serilog.Events;
using XiheNet.Data;
using Com.Common;
using Com.Core.Module.Implementations;
using XiheNet;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();

// 配置Json返回格式
builder.Services.AddControllers().AddJsonOptions(options => {
    options.JsonSerializerOptions.PropertyNamingPolicy = null;
});

// 配置Json返回格式
builder.Services.AddControllers().AddJsonOptions(options => {
    options.JsonSerializerOptions.PropertyNamingPolicy = null;
}).ConfigureApiBehaviorOptions(options => {
    // 自定义模型验证错误的响应格式
    options.InvalidModelStateResponseFactory = context => {
        var response = new XResponse<object>();
        
        // 获取第一个验证错误
        var firstError = context.ModelState
            .Where(ms => ms.Value?.Errors.Any() ?? false)
            .Select(ms => new {
                Field = ms.Key,
                Error = ms.Value?.Errors.First().ErrorMessage
            })
            .FirstOrDefault();

        // 创建统一格式的错误响应
        response.RespHead = new XRespHead
        {
            Code = "2100",
            Message = firstError?.Error ?? "数据验证失败"
        };
        
        // 返回200状态码，但响应体包含错误信息
        return new ObjectResult(response) { StatusCode = StatusCodes.Status200OK };
    };
});

// 跨域设置
builder.Services.AddCors(options => {
    options.AddPolicy
    (name: "XiheCors",
        builde => {
            builde.WithOrigins("*", "*", "*")
            .AllowAnyOrigin()
            .AllowAnyHeader()
            .AllowAnyMethod();
        }
    );
});

// 设置图形验证码
builder.Services.AddCaptcha(option =>
{
    option.CaptchaType = CaptchaType.WORD_NUMBER_LOWER;         // 验证码类型，如数字、字母等
    option.CodeLength = 4;                                      // 验证码长度
    option.ExpirySeconds = 120;                                 // 验证码过期时间（秒）
    option.IgnoreCase = true;                                   // 验证时是否忽略大小写
    option.ImageOption.Animation = false;                       // 是否启用动画（GIF）
    option.ImageOption.Width = 150;                             // 图片宽度
    option.ImageOption.Height = 50;                             // 图片高度
});

// AddSingleton()方法创建一个Singleton服务，首次请求会创建服务，然后，所有后续的请求中都会使用相同的实例，整个应用程序生命周期都使用该单个实例
// AddScoped():不同http清求，实例不同，同名谓词不同，也不行。例如httpget跟httppost,作用域是一定范围内，例如从同一个post请求的create方法，只能统计一次，每次请求都是新的实例
// AddTransient()：临时服务，每次请求时，都会创建一个新的Transient服务实例

#region 注册系统服务
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
#endregion

#region 注册XiheNet
builder.Services.RegisterDBHelper(builder.Configuration);               // 注册数据库连接服务
#endregion

#region 注册本项目服务
builder.Services.Configure<SiteConfig>(builder.Configuration.GetSection("SiteConfig"));
#endregion

// 注册事务过滤器
builder.Services.AddControllers(options => 
{
    options.Filters.Add<TransactionalFilter>();                     // 数据事务
    options.Filters.Add<UnifiedErrorFilter>();                      // 统一错误处理（模型验证+异常处理）
});

// 注册授权过滤器为服务
builder.Services.AddScoped<JwtAuthAttribute>();


// 新增模块注册，自动注册所有实现了IModule的模块
builder.Services.AddApplicationModules(builder.Configuration);

// 使用日志
builder.Host.UseSerilog((context, logger) => {
	// 读取配置文件
    logger.ReadFrom.Configuration(context.Configuration);
    logger.Enrich.FromLogContext();

	// 输出到Console控制台
    logger.WriteTo.Console();

	// 定义日志输出模板
	string SerilogOutputTemplate = "时间:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}等级:{Level}{NewLine}来源:{SourceContext}{NewLine}日志:{Message}{NewLine}{Exception}{NewLine}";

	// 输出到配置的文件日志目录
    string serilogDebug = System.Environment.CurrentDirectory + "\\Logs\\2 - Debug\\.log";
    logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Debug).WriteTo.Async(a => a.File(serilogDebug, rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)));
    string serilogInfo = System.Environment.CurrentDirectory + "\\Logs\\3 - Info\\.log";
    logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Information).WriteTo.Async(a => a.File(serilogInfo, rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)));
    string serilogWarn = System.Environment.CurrentDirectory + "\\Logs\\4 - Warning\\.log";
    logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Warning).WriteTo.Async(a => a.File(serilogWarn, rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)));
    string serilogError = System.Environment.CurrentDirectory + "\\Logs\\5 - Error\\.log";
    logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Error).WriteTo.Async(a => a.File(serilogError, rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)));
    string serilogFatal = System.Environment.CurrentDirectory + "\\Logs\\6 - Fatal\\.log";
    logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Fatal).WriteTo.Async(a => a.File(serilogFatal, rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)));
});

var app = builder.Build();

// 添加环境信息日志
app.Logger.LogInformation($"当前运行环境: {app.Environment.EnvironmentName}");

// 设置默认首页
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
}

// 设置默认首页
DefaultFilesOptions defaultFilesOptions = new DefaultFilesOptions();
defaultFilesOptions.DefaultFileNames.Clear();
defaultFilesOptions.DefaultFileNames.Add("index.html");
app.UseDefaultFiles(defaultFilesOptions);

// 配置静态文件中间件，为 .md 文件设置正确的 Content-Type 和字符集
var staticFileOptions = new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        var path = ctx.Context.Request.Path.Value?.ToLower() ?? "";
        if (path.EndsWith(".md"))
        {
            ctx.Context.Response.ContentType = "text/markdown; charset=utf-8";
        }
    }
};
app.UseStaticFiles(staticFileOptions);

// 动态资源
app.UseStaticFiles();

// 模块中间件配置
app.UseApplicationModules();

app.UseRouting();

// 使用跨域
app.UseCors("XiheCors");

// Razor页面和控制器
app.MapRazorPages();
app.MapControllers();

// 使用VueRouterHistory中间件
app.UseVueRouterHistory();

app.Run();
